import numpy as np
import pandas as pdPandas 기본기 | 행과 열의 선택
pandas
pandas에서 행과 열을 선택하는 기술에 대해서 알아보도록 하자!
해당 포스트는 전북대학교 통계학과 최규빈 교수님의 강의내용을 토대로 재구성되었음을 알립니다.
1. 라이브러리 import
2. pandas : 행과 열의 선택
- 같은 자료, 다른 두 형태의 데이터프레임
df = pd.DataFrame({'date': ['12/30','12/31','01/01','01/02','01/03'], 'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]})
df| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
| 3 | 01/02 | 55 | 80 | 75 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
얘는 인덱스는 그저 숫자의 의미이고
ts = pd.DataFrame({'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]}, index=['12/30','12/31','01/01','01/02','01/03'])
ts ## 중요한 코드는 아님, 근데 그냥 index 지정해주는 거잖아| X1 | X2 | X3 | X4 | |
|---|---|---|---|---|
| 12/30 | 65 | 55 | 50 | 40 |
| 12/31 | 95 | 100 | 50 | 80 |
| 01/01 | 65 | 90 | 60 | 30 |
| 01/02 | 55 | 80 | 75 | 80 |
| 01/03 | 80 | 30 | 30 | 100 |
얘는 인덱스에 시계열적 표현이 있다.
ts.reset_index() ## 결국 이렇게 하는 게 다루기 편하다.| index | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
| 3 | 01/02 | 55 | 80 | 75 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
안바꾸고 냅두는 경우,
index가 time seat를 의미하는 경우에는 안바꾸기도 한다. ~근데 위는 왜 다시 바꾼거~
A. 열의 선택
1번째 방법 :
df.ㆍ! 치명적인 단점 : 변수 이름에 공백 등이 있으면 불러올 수 없음.
df.X1 ## df 또한 하나의 object이므로0 65
1 95
2 65
3 55
4 80
Name: X1, dtype: int64
- 2번째 방법 :
df['ㆍ'],df[['ㆍ']]
df['X1'] ## df를 일종의 딕셔너리처럼 취급하는 방법0 65
1 95
2 65
3 55
4 80
Name: X1, dtype: int64
Series로 불러온다.
dictionary?
dct = dict({'date': ['12/30','12/31','01/01','01/02','01/03'], 'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]})
dct['X1'][65, 95, 65, 55, 80]
df.keys()Index(['date', 'X1', 'X2', 'X3', 'X4'], dtype='object')
dct.keys()dict_keys(['date', 'X1', 'X2', 'X3', 'X4'])
key와 value가 있는 것처럼 column의 한 값(key)에 대한 데이터(value)가 있는 모습이다.
df[['X1']] ## 프레임으로 산출| X1 | |
|---|---|
| 0 | 65 |
| 1 | 95 |
| 2 | 65 |
| 3 | 55 |
| 4 | 80 |
df[['X1', 'X2']] ## 2개 이상 산출 가능| X1 | X2 | |
|---|---|---|
| 0 | 65 | 55 |
| 1 | 95 | 100 |
| 2 | 65 | 90 |
| 3 | 55 | 80 |
| 4 | 80 | 30 |
- 3번째 방법 :
df.iloc[:, ㆍ]> 통째로 np.array와 같다고 보면 된다.
df.iloc[:, 0] ## numpy에서 행렬을 다루는 것과 완전히 같게 사용 가능.0 12/30
1 12/31
2 01/01
3 01/02
4 01/03
Name: date, dtype: object
#df.iloc[:,0] ## int - 0번째 행 | [0]이면 데이터프레임으로
#df.iloc[:,-2:] # int:int, -2번째 행부터 -1번째 행까지(뒤에서 두 개)
#df.iloc[:,1::2] # int:int:int - 스트라이딩, 1번째(두번째) 행부터 2개 단위로 추출
#df.iloc[:,[0,2]] # [int,int] - 특정 행(0, 2번째)을 데이터프레임의 형태로 반환
#df.iloc[:,[True,True,False,False,False]] # bool의 list
#df.iloc[:,range(2)] # range, 앞에서 2개- 4번째 방법 :
df.loc[:, ㆍ]> 완전히 새로운 방법
#df.loc[:,'X1'] # str - 시리즈 | ['X1']이면 데이터프레임으로
#df.loc[:,'X1':'X3'] # 'str':'str' -- 칼럼이름으로 슬라이싱 **
#df.loc[:,'X1'::2] # 'str'::int -- 칼럼이름으로 스트라이딩 **
#df.loc[:,['X1','X4']] # [str,str] - 특정 행만 데이터프레임으로
#df.loc[:,[True,False,False,True,False]] # bool의 list
"""
그냥 왠만해선 다 됨
"""- 'date'행 부터
df.loc[:, 'date':]| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
| 3 | 01/02 | 55 | 80 | 75 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
- True가 입력된 행만
df.loc[:, [True, False, True, False, True]] ## columns의 이름에 어떤 조건을 걸어서 True에 해당하는 열만 산출 가능| date | X2 | X4 | |
|---|---|---|---|
| 0 | 12/30 | 55 | 40 |
| 1 | 12/31 | 100 | 80 |
| 2 | 01/01 | 90 | 30 |
| 3 | 01/02 | 80 | 80 |
| 4 | 01/03 | 30 | 100 |
- 2칸씩 띄며 스트라이딩
df.loc[:, ::2] ## 2 간격으로 스트라이딩| date | X2 | X4 | |
|---|---|---|---|
| 0 | 12/30 | 55 | 40 |
| 1 | 12/31 | 100 | 80 |
| 2 | 01/01 | 90 | 30 |
| 3 | 01/02 | 80 | 80 |
| 4 | 01/03 | 30 | 100 |
B. 행의 선택
- 방법1 :
df[]
df[:2] ## int:int -- 슬라이싱 // df.iloc[:2, :], df.iloc[:2] 와 같음| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
df[::2] ## 스트라이딩, df.iloc[::2]와 같음| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
# df[:2] # int:int -- 슬라이싱 // df.iloc[:2,:], df.iloc[:2] 와 같음
# df[::2] # int:int -- 스트라이딩
# ts['12/30':'01/02'] # str:str -- 슬라이싱 > 인덱스가 문자열 등일 경우
# ts['12/31'::2] # str:str -- 스트라이딩
# df[['12' in date for date in df.date]] # [bool,bool] `12`가 데이터에 포함되어 있을 경우
# df[df.X1 < 70] # pd.Series([bool,bool])- 방법2 :
df.iloc[]
# df.iloc[0] # int df.iloc[0, :]에서 생략된 표현
# df.iloc[-2:] # int:int -- 슬라이싱
# df.iloc[1::2] # int:int -- 스트라이딩
# df.iloc[[0]] # [int]
# df.iloc[[0,1]] # [int,int]
# df.iloc[['12' in date for date in df.date]] # [bool,bool] 이 경우는 []와 동일하다.
# df.iloc[range(2)] # range- 해당 방법은 리스트나 어레이의 원소를 다루는 것과 완전히 동일해서… 아래를 참고하면 된다.
lst = [[1,2,3], [3,4,5]]
lst[0][1, 2, 3]
ary = np.array(lst)
ary[0]array([1, 2, 3])
- 방법3 :
df.loc[]
# df.loc[0] # int
# ts.loc['12/30'] # str
# df.loc[:2] # int:int
# ts.loc[:'01/02'] # str:str
# df.loc[[0,1]] # [int,int]
# ts.loc[['12/30','01/01']] # [str,str]
# df.loc[['12' in date for date in df.date]] # [bool,bool] 이 경우는 []와 동일하다.
# df.loc[df.X1>70] # pd.Series([bool,bool]) df.loc[:2] ## character와 비슷한 형식이기 때문에 2까지 포함이 된다.| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
df.loc[df.X1 > 70]| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
df.loc[df.X1 > 70]| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
위처럼 튜플로 넣을 수도 있다. 근데 iloc의 경우 위와 같은 코드로 입력하면 오류가 난다.
## df.iloc[df.X1 > 70] > 오류, bool을 받을 수 있으나, 튜플의 형태로 들어가면 반환하지 않는다.
df.iloc[list(df.X1 > 70)]| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
D. 교수님 방식
-가장 안전한 코드
df.loc[:,:] ## 해당 코드를 써놓고 시작, generally| date | X1 | X2 | X3 | X4 | |
|---|---|---|---|---|---|
| 0 | 12/30 | 65 | 55 | 50 | 40 |
| 1 | 12/31 | 95 | 100 | 50 | 80 |
| 2 | 01/01 | 65 | 90 | 60 | 30 |
| 3 | 01/02 | 55 | 80 | 75 | 80 |
| 4 | 01/03 | 80 | 30 | 30 | 100 |
- 하나의 col을 뽑으려 할 때
# df.X1 ## 제일 간단함. 게다가 눌러보면 변수 이름들이 나옴
# df['X1']
# df[['X1']]- row를 슬라이싱
# df[:5]
# ts[:'01/02'] # 시계열일 경우- 조건에 맞는 row를 뽑을 때 좋은 코드
# df[df.X1<60] ## 이게 좋기는 한데, True, False를 직접 만들어야 하는 경우도 많음.
# df.loc[['12' in date for date in df.date]]['12' in date for date in df.date][True, True, False, False, False]
- 하나의 row를 뽑으려 할 때 좋은 코드
# df.iloc[0]
# df.loc[0]ts.iloc[[0]]
# ts.iloc[0]의 경우 오류가 남(인덱스 이름이 숫자열이 아님| X1 | X2 | X3 | X4 | |
|---|---|---|---|---|
| 12/30 | 65 | 55 | 50 | 40 |
- (row,col)을 뽑으려 할 때 좋은 코드
# df.X1[0] ## <- pd.Series를 뽑고 인덱스로 접근
# df['X1'][0]
# df.iloc[0,0]
# df.loc[0,'X1']*위의 상황 이외에는 df.loc[:,:]를 사용하는 것이 유리하다.
요약
알아두면 좋은 규칙
.iloc[] 와 .iloc[,:]는 완전히 동등하다.
.loc[] 와 .loc[,:]는 완전히 동등하다.
결과를 pd.Series 형태가 아닌 pd.DataFrame 형태로 얻고 싶다면 [[?]]를 사용하면 된다.
ROW
| type of indexer | . |
[] |
.iloc |
.loc |
내가 쓴다면? |
|---|---|---|---|---|---|
| int | X | X | O | \(\Delta\) | df.iloc[3,:] |
| int:int | X | O | O | \(\Delta\) | df[3:5] |
| [int,int] | X | X | O | \(\Delta\) | df.iloc[idx,:] |
| str | X | X | X | O | ts.loc['time1',:] |
| str:str | X | O | X | O | ts.loc['time1':'time2',:] |
| [str,str] | X | X | X | O | 안할 듯 |
| [bool,bool] | X | O | O | O | df[filtered_idx] |
| pd.Series([bool,bool]) | X | O | X | O | df[df.X1>20] |
COL
| type of indexer | target | . |
[] |
.iloc |
.loc |
내가 쓴다면? |
|---|---|---|---|---|---|---|
| int | col | X | X | O | X | df.iloc[:,0] |
| int:int | col | X | X | O | X | df.iloc[:,0:2] |
| [int,int] | col | X | X | O | X | df.iloc[:,idx] |
| str | col | O | O | X | O | df.loc[:,'X1'] |
| str:str | col | X | X | X | O | df.loc[:,'X1':'X4'] |
| [str,str] | col | X | O | X | O | df.loc[:,colname_list] |
| [bool,bool] | col | X | X | O | O | df.loc[:,bool_list] |